#include <iostream>
#include <memory>
#include <string>
#include <cstring>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "thread.hpp"
using namespace The_Thread;
int InitClient() //建立客户端，返回文件描述符
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //建立套接字，成功返回文件描述符，失败返回-1，错误码被设置
    if(sockfd < 0)
    {
        std::cerr << "socket create error" << std::endl;
        exit(1);
    }
    return sockfd;
}
void RecvMessage(int sockfd, const std::string& name) //线程执行函数，进行接收信息
{
    while(true)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        char buffer[1024];
        int n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len); //接受服务器发来的信息，把服务器的sockaddr_in结构体（即套接字信息）信息填入到temp，以此判断接收到的是哪一个服务器发来的消息
        if(n > 0)
        {
            buffer[n] = 0;
            std::cerr << buffer << std::endl;
        }
        else
        {    
            std::cerr << "recvfrom error" << std::endl;
            break;
        }
    }
}
void SendMessage(int sockfd, std::string serverip , uint16_t serverport ,const std::string& name) //线程执行函数，进行发送信息
{
    struct sockaddr_in server; //存储服务器相关信息
    memset(&server, 0, sizeof server); //清空内容
    server.sin_family = AF_INET; //填写服务器地址类型
    server.sin_addr.s_addr = inet_addr(serverip.c_str()); //填写服务器ip，需要转成网络字节序
    server.sin_port = htons(serverport); //填写服务器端口号，需要转成网络字节序
    std::string cli_profix = name + "# "; //sender-thread# 
    while(true)
    {
        std::string line;
        std::cout << cli_profix;
        std::getline(std::cin, line); //从标准输入获取一行
        //std::cout << "getline message@ " << line << std::endl;
        int n = sendto(sockfd, line.c_str(), line.size(), 0, (struct sockaddr*)&server, sizeof server); //向server指向的ip和端口号对应的服务器发送消息
        if(n < 0)
            break;
    }
}
int main(int argc, char* argv[]) //命令行参数获取服务器端的ip地址和端口号
{
    if(argc != 3)
    {
        std::cerr << "Usage: " << "server_ip server_port" << std::endl;
        exit(0);
    }
    std::string ip = argv[1]; //获取ip
    uint16_t port = std::stoi(argv[2]); //获取端口号
    int sockfd = InitClient(); //获取文件描述符
    Thread recver("recver-thread", std::bind(&RecvMessage, sockfd, std::placeholders::_1)); //将接收消息的函数做绑定传给线程执行
    Thread sender("sender-thread", std::bind(&SendMessage, sockfd, ip, port, std::placeholders::_1)); //将发送消息的函数做绑定传给线程执行
    recver.Start(); //接收消息线程启动
    sender.Start(); //发送消息线程启动
    recver.Join(); //等待回收接收线程
    sender.Join(); //等待回收发送线程
    ::close(sockfd); //关闭文件
    return 0;
}
